import datetime

from django.db import transaction
from django.db.models import Sum
from rest_framework import serializers
from rest_framework.serializers import ModelSerializer

from finance.api.utils import update_account, increase_account_amount
from finance.models import CapitalAccount, RepaymentBill, FundBill, Journal, Prepayment


class AccountSerializer(ModelSerializer):
    """
    资金账号
    """

    class Meta:
        model = CapitalAccount
        fields = ["id", "name", "default"]


class CapitalAccountSerializer(ModelSerializer):
    """
    资金账号
    """
    account_type_name = serializers.CharField(source='get_account_type_display', read_only=True)
    default_name = serializers.CharField(source='get_default_display', read_only=True)

    class Meta:
        model = CapitalAccount
        exclude = ["update_time", "add_time"]


class RepaymentBillSerializer(ModelSerializer):
    """还款记录"""
    user_name = serializers.CharField(source='user.real_name', read_only=True)

    class Meta:
        model = RepaymentBill
        exclude = ['update_at', 'create_at']

    def create(self, validated_data):
        print(validated_data)
        with transaction.atomic():
            # 创建事务保存点
            save_id = transaction.savepoint()
            instance = None
            try:
                instance = self.Meta.model.objects.create(**validated_data)
                # results = self.Meta.model.objects.filter(bill=instance.bill).aggregate(total_money=Sum('money'))
                # bill = instance.bill
                # bill.repayment = results.get('total_money') or 0
                # bill.save(update_fields=['repayment'])
                account_id = instance.bill.account_id
                money = instance.money if instance.bill.category == 2 else instance.money * -1
                update_account(account_id, money)
            except Exception as e:
                print(e)
                transaction.savepoint_rollback(save_id)

            transaction.savepoint_commit(save_id)
        return instance


class FundBillSerializer(ModelSerializer):
    """资金账单"""
    employee_name = serializers.CharField(source='employee.name', read_only=True)
    category_name = serializers.CharField(source='get_category_display', read_only=True)
    account_name = serializers.CharField(source='account.name', read_only=True)
    title_name = serializers.CharField(source='acc_title.name', read_only=True)
    user_name = serializers.CharField(source='user.real_name', read_only=True)
    verify_name = serializers.CharField(source='get_verify_display', read_only=True)
    repayment = serializers.SerializerMethodField(read_only=True)
    balance = serializers.SerializerMethodField(read_only=True)
    repayments = RepaymentBillSerializer(many=True, read_only=True)

    class Meta:
        model = FundBill
        exclude = ['update_at', 'create_at']

    def get_balance(self, obj):
        return obj.money - obj.get_repayment()

    def get_repayment(self, obj):
        return obj.get_repayment()

    def create(self, validated_data):
        with transaction.atomic():
            # 创建事务保存点
            save_id = transaction.savepoint()
            instance = None
            try:
                instance = self.Meta.model.objects.create(**validated_data)
                if instance.verify == 1:
                    self.update_account(instance)
            except Exception as e:
                print(e)
                transaction.savepoint_rollback(save_id)

            transaction.savepoint_commit(save_id)
        return instance

    def update(self, instance, validated_data):
        with transaction.atomic():
            # 创建事务保存点
            save_id = transaction.savepoint()
            try:
                instance.order_no = validated_data.get('order_no', instance.order_no)
                instance.employee = validated_data.get('employee', instance.employee)
                instance.acc_title = validated_data.get('acc_title', instance.acc_title)
                instance.account = validated_data.get('account', instance.account)

                instance.money = validated_data.get('money', instance.money)
                instance.order_time = validated_data.get('order_time', instance.order_time)
                instance.category = validated_data.get('category', instance.category)

                instance.desc = validated_data.get('desc', instance.desc)
                instance.source = validated_data.get('source', instance.source)
                instance.user = validated_data.get('user', instance.user)
                old_verify = instance.verify
                instance.verify = validated_data.get('verify', instance.verify)

                instance.save()
                if (old_verify == 0 or old_verify is None) and instance.verify == 1:
                    self.update_account(instance)
            except Exception as e:
                print(e)
                transaction.savepoint_rollback(save_id)

            transaction.savepoint_commit(save_id)

        return instance

    def update_account(self, obj):
        if obj.category == 0 or obj.category == 3:   # 费用/借出
            update_account(obj.account_id, obj.money)
        elif obj.category == 1 or obj.category == 2:     # 收入/借入
            update_account(obj.account_id,  -1 * obj.money)


class JournalSerializer(ModelSerializer):
    """流水账"""
    customer_name = serializers.SerializerMethodField()
    account_name = serializers.CharField(source='account.name', read_only=True)
    user_name = serializers.CharField(source='user.real_name', read_only=True)
    account_balance = serializers.SerializerMethodField()

    class Meta:
        model = Journal
        exclude = ['update_at', 'create_at']

    def get_account_balance(self, obj):
        return (obj.balance + obj.money) if obj.balance else (0 + obj.money)

    def get_customer_name(self, obj):
        return obj.customer.name if obj.customer else obj.name


class PrepaymentSerializer(ModelSerializer):
    """预收款"""
    customer_name = serializers.CharField(source='customer.name', read_only=True)
    account_name = serializers.CharField(source='account.name', read_only=True)
    user_name = serializers.CharField(source='user.real_name', read_only=True)
    oper_user_name = serializers.CharField(source='oper_user.real_name', read_only=True)

    class Meta:
        model = Prepayment
        exclude = ['update_at', 'create_at']

    def create(self, validated_data):
        with transaction.atomic():
            # 创建事务保存点
            save_id = transaction.savepoint()
            instance = None
            try:
                order_time = validated_data.get("order_time", None)
                if not order_time:
                    validated_data["order_time"] = datetime.datetime.now()
                instance = self.Meta.model.objects.create(**validated_data)
                if instance.flag == 0:
                    self.update_account(instance)
            except Exception as e:
                print(e)
                transaction.savepoint_rollback(save_id)

            transaction.savepoint_commit(save_id)
        return instance

    def update(self, instance, validated_data):
        with transaction.atomic():
            save_id = transaction.savepoint()
            try:
                instance.code = validated_data.get('code', instance.code)
                instance.order_time = validated_data.get('order_time', instance.order_time)
                instance.customer = validated_data.get('customer', instance.customer)
                instance.user = validated_data.get('user', instance.user)

                old_amount = instance.amount

                instance.amount = validated_data.get('amount', instance.amount)
                instance.deduct_amount = validated_data.get('deduct_amount', instance.deduct_amount)
                instance.flag = validated_data.get('flag', instance.flag)

                account_id = instance.account_id

                instance.account = validated_data.get('account', instance.account)
                instance.remark = validated_data.get('remark', instance.remark)
                instance.oper_user = validated_data.get('oper_user', instance.oper_user)

                if instance.flag == 0:
                    increase_account_amount(account_id, -1 * old_amount, instance.customer_id)

                instance.save()

                if instance.flag == 0:
                    self.update_account(instance)
            except Exception as e:
                print(e)
                transaction.savepoint_rollback(save_id)

            transaction.savepoint_commit(save_id)

        return instance

    def update_account(self, obj):
        increase_account_amount(obj.account_id, obj.amount, obj.customer_id)


